<?php

namespace Fluency\Web\Routing;

use Fluency\Web\Http\Request;
use Fluency\Web\RequestDispatcher;

/**
 * A router that splits URLs on slashes, tries to compose the action name from the fewest segments
 * and uses the remainder as request parameter key/value pairs. For example, if an action called
 * "posts/index" exists, then the URL /posts/index and /posts/index/id/1 both map to that action,
 * but the second one also sets the "id" request parameter to 1.
 *
 * @package Fluency\Web\Routing
 * @author  Ignas Rudaitis
 * @since   1.0
 */
class PathRouter implements Router
{
    private $dispatcher;
    private $maxActionDepth;

    /**
     * The constructor.
     *
     * @param Fluency\Web\RequestDispatcher $dispatcher the dispatcher to associate requests with
     * @param integer $maxActionDepth a limit for the number of segments the action name is
     *        composed of (0 means no limit)
     */
    public function __construct(RequestDispatcher $dispatcher, $maxActionDepth = 5)
    {
        $this->dispatcher = $dispatcher;
        $this->maxActionDepth = $maxActionDepth;
    }

    /**
     * @see Fluency\Web\Routing\Router::query()
     *
     * @param string $url
     * @return Fluency\Web\Http\Request|null
     */
    public function query($url)
    {
        $url = str_replace("//", "/", trim($url, "/"));
        $segments = explode("/", $url);
        for ($i = 1; $i <= count($segments); $i++) {
            if ($i == $this->maxActionDepth) {
                return null;
            }
            $action = join("/", array_slice($segments, 0, $i));
            $request = $this->dispatcher->createRequest()->forAction($action);
            if ($request->isExecutable()) {
                $params = array();
                $remainder = array_slice($segments, $i);
                if (count($remainder) % 2 == 1) {
                    array_pop($remainder);
                }
                for ($j = 0; $j < count($remainder); $j += 2) {
                    $params[$remainder[$j]] = $remainder[$j + 1];
                }
                return $request->withParams($params);
            }
        }
    }
}
